;-------------------------------------------------------------------------------
format ELF64 executable
entry start

SDL_OPENGL = 0x04000000
SDL_NOFRAME = 0x02000000
SDL_KEYDOWN = 0x300

GL_FRAGMENT_SHADER = 0x8B30

DEBUG = 0

macro emit [param] {param}
;-------------------------------------------------------------------------------
include 'import64.inc'
interpreter '/lib64/ld-linux-x86-64.so.2'
needed 'libdl.so.2'
import dlopen,dlsym
;-------------------------------------------------------------------------------
segment readable writeable executable

start:
    sub rsp,2048
    ; define local variables
    emit <event equ rsp+1024>,<log equ rsp>
    mov r13,[dlsym]
if DEBUG = 1
    ; load libc
    emit <mov rdi,g_str_libc>,<xor esi,esi>,<inc esi>,<call [dlopen]>,<mov [g_libc],rax>
    emit <mov rdi,[g_libc]>,<mov rsi,g_str_printf>,<call r13>,<mov [printf],rax>
end if
    ; load SDL library
    emit <mov rdi,g_str_libsdl>,<xor esi,esi>,<inc esi>,<call [dlopen]>,<mov r12,rax>
    ; SDL_SetVideoMode
    emit <mov rdi,r12>,<mov rsi,g_str_SDL_SetVideoMode>,<call r13>
    emit <mov edi,1280>,<mov esi,720>,<xor edx,edx>,<mov ecx,SDL_OPENGL+SDL_NOFRAME>,<call rax>
    ; load needed SDL functions
    emit <mov rdi,r12>,<mov rsi,g_str_SDL_GL_GetProcAddress>,<call r13>,<mov rbx,rax>
    ; create program
    emit <mov rdi,g_str_glCreateShaderProgramv>,<call rbx>
    emit <mov edi,GL_FRAGMENT_SHADER>,<mov esi,1>,<mov rdx,g_src_fs_ptr>,<call rax>,<mov r15d,eax>
    ; use program
    emit <mov rdi,g_str_glUseProgram>,<call rbx>
    emit <mov edi,r15d>,<call rax>
if DEBUG = 1
    ; print GLSL info log
    emit <mov rdi,g_str_glGetProgramInfoLog>,<call rbx>
    emit <mov edi,r15d>,<mov esi,1024>,<xor edx,edx>,<lea rcx,[log]>,<call rax>
    emit <mov rdi,g_str_log>,<lea rsi,[log]>,<call [printf]>
end if
      .main_loop:
    ; process window events
    emit <mov rdi,r12>,<mov rsi,g_str_SDL_PollEvent>,<call r13>
    emit <lea rdi,[event]>,<call rax>
    cmp dword [event],SDL_KEYDOWN
    je .main_loop_end
    ; get time
    emit <mov rdi,r12>,<mov rsi,g_str_SDL_GetTicks>,<call r13>,<call rax>,<mov r14d,eax>
    emit <mov rdi,g_str_glTexCoord1f>,<call rbx>
    emit <cvtsi2ss xmm0,r14d>,<call rax>
    ; draw
    emit <mov rdi,g_str_glRecti>,<call rbx>
    emit <mov edi,-1>,<mov esi,-1>,<mov edx,1>,<mov ecx,1>,<call rax>
    ; swap
    emit <mov rdi,r12>,<mov rsi,g_str_SDL_GL_SwapBuffers>,<call r13>,<call rax>
    jmp .main_loop
      .main_loop_end:
    ; terminate process
    emit <mov eax,60>,syscall
;-------------------------------------------------------------------------------
align 1
g_src_fs:
db  'float t;'
db  'vec3 mod289(vec3 x){'
db      'return x-floor(x*(1./289.))*289.;'
db  '}'
db  'vec3 permute(vec3 x){'
db      'return mod289(((x*34.)+1.)*x);'
db  '}'
db  'float snoise(vec2 v){'
db      'vec4 C=vec4(.2113,.3660,-.5773,.0243);'
db      'vec2 i=floor(v+dot(v,C.yy));'
db      'vec2 x0=v-i+dot(i,C.xx);'
db      'vec2 i1=(x0.x>x0.y)?vec2(1,0):vec2(0,1);'
db      'vec4 x12=x0.xyxy+C.xxzz;'
db      'x12.xy-=i1;'
db      'i=i-floor(i*(1./289.))*289.;'
db      'vec3 p=permute(permute(i.y+vec3(0,i1.y,1))+i.x+vec3(0,i1.x,1));'
db      'vec3 m=max(.5-vec3(dot(x0,x0),dot(x12.xy,x12.xy),dot(x12.zw,x12.zw)),0);'
db      'm=m*m;'
db      'm=m*m;'
db      'vec3 x=2.*fract(p*C.www)-1.;'
db      'vec3 h=abs(x)-.5;'
db      'vec3 ox=floor(x+.5);'
db      'vec3 a0=x-ox;'
db      'm*=1.7928-.8537*(a0*a0+h*h);'
db      'vec3 g;'
db      'g.x=a0.x*x0.x+h.x*x0.y;'
db      'g.yz=a0.yz*x12.xz+h.yz*x12.yw;'
db      'return 130.*dot(m,g);'
db  '}'
db  'void main(){'
db      't=gl_TexCoord[0].s*.001;'
db      'float x=gl_FragCoord.x/1280.;'
db      'float y=gl_FragCoord.y/720.;'
db      'gl_FragColor=abs(sin(vec4(t+7.*snoise(vec2(2.*x,y)),.5*t+10.*snoise(vec2(.7*x,.4*y)),1.3*t+2.*snoise(vec2(4.*x,3.*y)),1.)));'
db  '}',0

g_str_libsdl db 'libSDL-1.3.so.0',0
g_str_SDL_SetVideoMode db 'SDL_SetVideoMode',0
g_str_SDL_PollEvent db 'SDL_PollEvent',0
g_str_SDL_GL_SwapBuffers db 'SDL_GL_SwapBuffers',0
g_str_SDL_GetTicks db 'SDL_GetTicks',0
g_str_SDL_GL_GetProcAddress db 'SDL_GL_GetProcAddress',0
g_str_glCreateShaderProgramv db 'glCreateShaderProgramv',0
g_str_glRecti db 'glRecti',0
g_str_glUseProgram db 'glUseProgram',0
g_str_glTexCoord1f db 'glTexCoord1f',0
if DEBUG = 1
g_str_libc db 'libc.so.6',0
g_str_printf db 'printf',0
g_str_glGetProgramInfoLog db 'glGetProgramInfoLog',0
g_str_log db 'GLSL info log:',10,'%s',10,0
g_str_d db '%d',10,0
g_str_p db '%p',10,0
end if

align 8
g_src_fs_ptr dq g_src_fs

if DEBUG = 1
g_libc dq 0
printf dq 0
end if
;-------------------------------------------------------------------------------
